/*
 * Copyright (c) 2024 Black Sesame Technologies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "dal_utils/MsgLibLoader.hpp"

std::unordered_map<std::string, void*> MsgLibLoader::libraryMap_;
std::unordered_map<std::string, const void*> MsgLibLoader::typeSupportMap_;

bool MsgLibLoader::loadLibrary(const std::string& input)
{
    std::string aa, bb, cc;
    if (!parseInput(input, aa, bb, cc)) {
        std::cerr << "Invalid input format: " << input << std::endl;
        return false;
    }

    std::string libraryName = "lib" + aa + "__dalidl_typesupport_cpp.so";
    void* handle = dlopen(libraryName.c_str(), RTLD_LAZY);
    if (handle) {
        libraryMap_[input] = handle;
        return true;
    }

#if defined (__x86_64__)
    std::string prefix = "/opt/cyber/usr/lib/";
#elif defined (__android_aarch64__)
    std::string prefix = "/vendor/lib64/";
#else
    std::string prefix = "/usr/lib/";
#endif

    std::string libraryNameTmp = prefix + libraryName;
    handle = dlopen(libraryNameTmp.c_str(), RTLD_LAZY);
    if (handle) {
        libraryMap_[input] = handle;
        return true;
    }

    std::cerr << "Failed to load shared library: " << libraryName << " - " << dlerror()
              << std::endl;
    return false;
}

void* MsgLibLoader::getFunction(const std::string& input)
{
    std::string aa, bb, cc;
    if (!parseInput(input, aa, bb, cc)) {
        std::cerr << "Invalid input format: " << input << std::endl;
        return nullptr;
    }

    if (libraryMap_.find(input) == libraryMap_.end()) {
        std::cerr << "Library not loaded for input: " << input << std::endl;
        return nullptr;
    }

    void* handle = libraryMap_[input];
    std::string functionName =
        "dalidl_typesupport_cpp__get_message_type_support_handle__" + aa + "__" + bb + "__" + cc;
    void* function = dlsym(handle, functionName.c_str());
    if (!function) {
        std::cerr << "Failed to load function: " << functionName << " - " << dlerror() << std::endl;
        return nullptr;
    }

    return function;
}

bool MsgLibLoader::parseInput(const std::string& input,
                              std::string& aa,
                              std::string& bb,
                              std::string& cc)
{
    size_t pos1 = input.find("::");
    size_t pos2 = input.find("::", pos1 + 2);
    if (pos1 == std::string::npos || pos2 == std::string::npos) {
        return false;
    }

    aa = input.substr(0, pos1);
    bb = input.substr(pos1 + 2, pos2 - pos1 - 2);
    cc = input.substr(pos2 + 2);
    return true;
}